package com.jzo2o.foundations.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.RegionMapper;
import com.jzo2o.foundations.mapper.RegionServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeItem;
import com.jzo2o.foundations.model.domain.ServeSearch;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.*;
import com.jzo2o.foundations.service.IRegionServeService;
import com.jzo2o.foundations.service.IServeItemService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;


import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * \* User: chy
 * \* Date: 2025/9/24  15:13
 * \* Description:
 * \
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RegionServeServiceImpl extends ServiceImpl<RegionServeMapper, Serve> implements IRegionServeService {
    private final RegionServeMapper regionServeMapper;
    private final RegionMapper regionMapper;
    private final IServeItemService serveItemService;
    private final RabbitTemplate rabbitTemplate;

    //定义售卖状态常量  售卖状态，0：草稿，1下架，2上架
    private static final Integer SALE_STATUS_DRAFT = 0;
    private static final Integer SALE_STATUS_OFF_SHELF = 1;
    private static final Integer SALE_STATUS_ON_SHELF = 2;
    //是否为热门，0非热门，1热门
    private static final Integer IS_HOT_NO = 0;
    private static final Integer IS_HOT_YES = 1;


    /**
     * 区域服务分页查询
     *
     * @param reqDTO
     * @return
     */
    @Override
    public PageResult<ServeResDTO> queryRegionServePage(ServePageQueryReqDTO reqDTO) {
        //1.分页查询
        Page<ServeResDTO> page = new Page<>(reqDTO.getPageNo(), reqDTO.getPageSize());

        List<ServeResDTO> serveList = regionServeMapper.serveList(page, reqDTO.getRegionId());

        return PageResult.of(serveList, reqDTO.getPageSize().intValue(), reqDTO.getPageNo(), page.getTotal());
    }

    /**
     * 批量新增区域服务
     *
     * @param resDTO
     */
    //todo :
    // 实现思路: 先去判断服务的状态,然后再判断是否重复添加
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#resDTO[0].regionId"),//删除小程序端已开通服务分类缓存
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#resDTO[0].regionId")//删除小程序端首页服务列表缓存
    })

    public void batchAddRegionServe(List<ServeUpsertReqDTO> resDTO) {
        log.info("批量新增区域服务");
        //获取服务项id
        List<Long> serveItemIds = resDTO.stream().map(ServeUpsertReqDTO::getServeItemId).collect(Collectors.toList());
        //获取区域id
        List<Long> regionIds = resDTO.stream().map(ServeUpsertReqDTO::getRegionId).collect(Collectors.toList());
        Long regionId = regionIds.get(0);

        //1.判断服务状态
        int serveStatus = getServeStatus(serveItemIds);
        if (serveStatus > 0) {
            throw new ForbiddenOperationException("服务状态异常");
        }
        //2.判断是否重复添加
        int judgedServeRepeat = judgeServeRepeat(serveItemIds, regionId);
        if (judgedServeRepeat > 0) {
            throw new ForbiddenOperationException("服务重复添加");
        }

        //3.查询regin拿到城市编码
        Region region = regionMapper.selectById(regionId);
        if (region == null) {
            throw new ForbiddenOperationException("城市编码不存在");
        }
        //4.封装数据并保存
        List<Serve> serves = resDTO.stream()
                .map(item -> {
                    Serve serve = new Serve();
                    serve.setServeItemId(item.getServeItemId());
                    serve.setRegionId(item.getRegionId());
                    serve.setPrice(item.getPrice());
                    serve.setCityCode(region.getCityCode());
                    serve.setHotTimeStamp(0L);
                    return serve;
                }).collect(Collectors.toList());
        super.saveBatch(serves);
//        // 拿到所有的服务id
//        List<Long> serveId = serves.stream().map(Serve::getId).collect(Collectors.toList());
//
//        try {
//            //4.发送消息给服务,同步到mq,用于小程序端能够搜索到实时的服务
//            rabbitTemplate.convertAndSend("serve-exchange", "serve-add-to-es", CollUtil.join(serveId, ",") );
//        } catch (AmqpException e) {
//            log.error("发送消息给服务失败:{}",e);
//        }
    }

    /**
     * 判断服务是否重复添加
     *
     * @param serveItemIds
     * @param regionId
     */
    private int judgeServeRepeat(List<Long> serveItemIds, Long regionId) {
        return super.count(Wrappers.<Serve>lambdaQuery()
                .eq(Serve::getRegionId, regionId)
                .in(Serve::getServeItemId, serveItemIds));
    }


    /**
     * 获取服务状态
     *
     * @param serveItemIds
     */
    private int getServeStatus(List<Long> serveItemIds) {

        return serveItemService.count(Wrappers.<ServeItem>lambdaQuery()
                .in(ServeItem::getId, serveItemIds)
                .ne(ServeItem::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus()));
    }

    /**
     * 根据serveId修改价格
     *
     * @param id
     * @param price
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, allEntries = true)//删除小程序端首页服务列表缓存
            , @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")//删除服务详情缓存
            , @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)//删除小程序热门服务列表
    })

    public void updateServePrice(Long id, BigDecimal price) {

        LambdaUpdateWrapper<Serve> wrapper = new LambdaUpdateWrapper<Serve>().eq(Serve::getId, id)
                .set(Serve::getPrice, price);
        boolean update = super.update(null, wrapper);
        if (!update) {
            throw new ForbiddenOperationException("修改失败");
        }
    }

    /**
     * 上架服务
     *
     * @param id
     */
    //todo: ampq同步修改es数据  监听的实体类为ServeSearchToEsListener类中
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, allEntries = true)//删除小程序端首页服务列表缓存
            , @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, allEntries = true)//删除小程序端已开通服务分类缓存
            , @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)//删除小程序热门服务列表
            , @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")//删除服务详情缓存
    })
    public void onSaleSaleStatus(Long id) {
        LambdaUpdateWrapper<Serve> wrapper = new LambdaUpdateWrapper<Serve>().eq(Serve::getId, id)
                .set(Serve::getSaleStatus, SALE_STATUS_ON_SHELF);
        boolean update = super.update(null, wrapper);
        if (!update) {
            throw new ForbiddenOperationException("修改失败");
        }
        try {
            //4.发送消息给服务,同步到mq,用于小程序端能够搜索到实时的服务
            rabbitTemplate.convertAndSend("serve-exchange", "serve-add-es", id + "");
        } catch (AmqpException e) {
            log.error("发送消息给服务失败:{}", e);
        }
    }

    /**
     * 下架服务
     *
     * @param id
     */
    //todo: ampq同步修改es数据  监听的实体类为ServeSearchToEsListener类中
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, allEntries = true)//删除小程序端首页服务列表缓存
            , @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, allEntries = true)//删除小程序端已开通服务分类缓存
            , @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)//删除小程序热门服务列表
            , @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")//删除服务详情缓存
    })
    public void offSaleSaleStatus(Long id) {
        LambdaUpdateWrapper<Serve> wrapper = new LambdaUpdateWrapper<Serve>().eq(Serve::getId, id)
                .set(Serve::getSaleStatus, SALE_STATUS_OFF_SHELF);//0：草稿，1下架，2上架
        boolean update = super.update(null, wrapper);
        if (!update) {
            throw new ForbiddenOperationException("修改失败");
        }
        try {
            //4.发送消息给服务,同步到mq,用于小程序端能够搜索到实时的服务
            rabbitTemplate.convertAndSend("serve-exchange", "serve-delete-es", id + "");
        } catch (AmqpException e) {
            log.error("发送消息给服务失败:{}", e);
        }
    }

    /**
     * 更新服务为热门服务
     *
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)//删除缓存
    public void updateOnHot(Long id) {
        LambdaUpdateWrapper<Serve> wrapper = new LambdaUpdateWrapper<Serve>()
                .eq(Serve::getId, id)
                .set(Serve::getIsHot, IS_HOT_YES);
        boolean update = super.update(null, wrapper);
        if (!update) {
            throw new ForbiddenOperationException("修改失败");
        }
    }

    /**
     * 更新服务为冷门服务
     *
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)//删除缓存
    public void updateOffHot(Long id) {

        LambdaUpdateWrapper<Serve> wrapper = new LambdaUpdateWrapper<Serve>()
                .eq(Serve::getId, id)
                .set(Serve::getIsHot, IS_HOT_NO);
        boolean update = super.update(null, wrapper);
        if (!update) {
            throw new ForbiddenOperationException("修改失败");
        }
    }

    /**
     * 根据regionId和saleStatus查询服务数量
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public int queryServeCountByRegionIdAndSaleStatus(Long id, int status) {
        LambdaQueryWrapper<Serve> wrapper = new LambdaQueryWrapper<Serve>()
                .eq(Serve::getRegionId, id)
                .eq(Serve::getSaleStatus, status);
        return super.count(wrapper);
    }

    /**
     * 小程序端首页服务列表
     * //todo 服务类型只返回2个   服务列表只返回4个
     *
     * @param regionId 区域id
     * @return 首页服务列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#p0", cacheManager = RedisConstants.CacheManager.FOREVER)
    public List<ServeCategoryResDTO> queryCategoryList(Long regionId) {
        log.info("查询服务列表");
        List<ServeCategoryResDTO> result = regionMapper.selectServeCategoryListByRegionId(regionId);
        if (CollectionUtils.isEmpty(result)) {
            return result;
        }
        //截取2个服务类型
        int limit = Math.min(result.size(), 2);
        result = result.stream().limit(limit).collect(Collectors.toList());
        //截取4个服务项
        for (ServeCategoryResDTO serveCategoryResDTO : result) {
            int limit2 = Math.min(serveCategoryResDTO.getServeResDTOList().size(), 4);
            List<ServeSimpleResDTO> serveSimpleResDTOList = serveCategoryResDTO.getServeResDTOList().stream().limit(limit2).collect(Collectors.toList());
            serveCategoryResDTO.setServeResDTOList(serveSimpleResDTOList);
        }
        return result;
    }

    /**
     * 小程序端首页热门服务列表
     *
     * @param regionId 区域id
     * @return 首页服务列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", cacheManager = RedisConstants.CacheManager.ONE_DAY)
    // 缓存到redis中
    public List<HotServeListResDTO> queryHotServeList(Long regionId) {
        log.info("获取热门服务列表区域id:{}", regionId);
        return regionMapper.selectHotServeList(regionId);
    }

    /**
     * 小程序端服务类型列表
     *
     * @param regionId 区域id
     * @return 服务类型列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", cacheManager = RedisConstants.CacheManager.FOREVER)
    public List<ServeAggregationTypeSimpleResDTO> getAllTypeByRegionId(Long regionId) {
        return regionMapper.selectAllTypeByRegionId(regionId);
    }

    /**
     * 小程序端服务详情
     *
     * @param id 服务id
     * @return 服务详情
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
    public ServeAggregationSimpleResDTO queryServeDetail(Long id) {

        return regionMapper.selectServeDetail(id);
    }

    /**
     * 根据服务id查询服务信息
     * <p>
     * 用于添加到es中用
     *
     * @param serveId 服务id
     * @return 服务信息
     */
    @Override
    public ServeSearch getServeSearchByServeId(Long serveId) {
        ServeSearch serveSearch = regionServeMapper.getServeSearchByServeId(serveId);
        return serveSearch;
    }
    /**
     * 根据服务id查询服务详情   这个接口主要给订单服务使用
     * @param id
     * @return
     */
    @Override
    public ServeAggregationResDTO queryServeById(Long id) {

        return regionServeMapper.getServeById( id);
    }


}
